Skip to content

Fix residual blog metadata from Ahrefs audit#7894

Merged
lawrencecchen merged 44 commits into
mainfrom
feat-seo-blog-audit
Jul 12, 2026
Merged

Fix residual blog metadata from Ahrefs audit#7894
lawrencecchen merged 44 commits into
mainfrom
feat-seo-blog-audit

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Stacked on #7888.

Selects complete, route-specific metadata for 11 blog families, /nightly, and /guides across published locales. HTML, Open Graph, Twitter, and article schema use the same selected copy. English-only cmux-omo and gpl URLs now canonicalize instead of publishing fallback duplicates.

Tests: bun test (591 passed, 91 skipped), bun run typecheck, changed-file ESLint.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

Medium Risk
Broad SEO and i18n routing changes affect canonical URLs, hreflang, and which locales can access several blog paths; mistakes could cause wrong redirects or indexing, but behavior is heavily tested.

Overview
Addresses residual Ahrefs blog SEO by routing 11 blog posts plus /nightly and /guides through shared audited helpers (blogPostSeoCopy, landingPageSeoCopy) so HTML metadata, Open Graph, Twitter, and article JSON-LD (BlogSchema + seoKey) use the same selected titles and descriptions, with title: { absolute: ... } on audited posts.

Locale availability is tightened for partially translated blogs: cmux-claude-teams, cmux-omo, and gpl are English-only; cmux-ssh stays en/ja. That registry drives buildAlternates, middleware redirects/canonical rewrites, Link hreflang headers, sitemap entries, blogPostsForLocale (index + pager), and agent .md/.txt variants so unsupported locales no longer surface duplicate or fallback URLs.

Adds blogPostSeoCopy with per-post prose candidate keys, landingPageSeoCopy for landing pages, and small message tweaks in a few locales; tests cover navigation filtering, alternates, middleware, sitemap, and agent variants.

Reviewed by Cursor Bugbot for commit e34583a. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Fixes residual blog SEO from the Ahrefs audit. Unifies metadata for 11 posts plus /nightly and /guides, enforces plain‑text titles/descriptions, and limits alternates, sitemap, navigation, agent variants, and routing to authored locales.

  • Bug Fixes
    • Route 11 audited posts through blogPostSeoCopy; set title: { absolute: ... }; pass seoKey to BlogSchema so JSON‑LD uses the same audited copy.
    • Use landingPageSeoCopy for /nightly and /guides with complete prose and page context.
    • Scope locales per route: /blog/cmux-claude-teams, /blog/cmux-omo, /blog/gpl are en‑only via englishFallbackContentLocales; /blog/cmux-ssh is en/ja. buildAlternates/Link headers, sitemap entries, agent‑readable variants, blog index, and pager expose only authored locales; middleware negotiates allowed locales per route, rewrites canonical routes, and 301s others.
    • Enforce plain‑text metadata (reject rich messages and list lead‑ins) and keep sentence‑level punctuation bounds; small i18n copy tweaks in en, bs, th, tr; tests cover alternates, sitemap, blog discovery, canonicalization, agent‑page variants, and punctuation rules.

Written for commit e34583a. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added audited SEO title/description support for blog structured data via an optional SEO key.
    • Improved blog/guide metadata generation to use centralized SEO-copy helpers and consistent alternates.
    • Blog navigation, listings, sitemap, and agent-readable routes now respect locale availability and fallbacks.
  • Bug Fixes

    • Fixed fallback-content locale negotiation and alternate-link headers to only target locales available for the requested path.
  • Content

    • Updated localized SEO copy for several blog entries and related meta descriptions.
  • Tests

    • Expanded SEO, routing, middleware, locale, and sitemap coverage for English-only and partially translated posts.

@vercel

vercel Bot commented Jul 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jul 12, 2026 9:14am
cmux-staging Building Building Preview, Comment Jul 12, 2026 9:14am

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Blog SEO and locale handling

Layer / File(s) Summary
Audited SEO copy and metadata
web/i18n/audited-seo.ts, web/app/[locale]/(landing)/blog/*/page.tsx, web/app/[locale]/(landing)/guides/page.tsx, web/app/[locale]/(landing)/nightly/page.tsx, web/app/[locale]/(landing)/blog/blog-schema.tsx, web/messages/*
Adds centralized audited SEO helpers, updates blog and landing-page metadata generation, and lets BlogSchema use audited copy through seoKey.
Per-route fallback locale handling
web/i18n/locale-availability.ts, web/proxy.ts, web/app/[locale]/(landing)/blog/cmux-claude-teams/page.tsx, web/app/[locale]/(landing)/blog/cmux-ssh/page.tsx
Associates fallback routes with available locales and applies those locales to negotiation, validation, alternate links, and metadata alternates.
Locale-aware blog indexes and route registries
web/app/[locale]/components/blog-posts.ts, web/app/[locale]/components/blog-pager.tsx, web/app/[locale]/(landing)/blog/page.tsx, web/app/lib/agent-page-paths.ts, web/app/sitemap.ts
Adds locale-filtered blog posts and records per-route locale availability across blog listings, agent-readable pages, and sitemap entries.
SEO and route validation
web/tests/seo.test.ts, web/tests/agent-page-variants.test.ts
Expands audited SEO checks and verifies canonical, sitemap, hreflang, and agent-page behavior for English-only and partially translated blog routes.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

SEO metadata flow

sequenceDiagram
  participant BlogPage
  participant blogPostSeoCopy
  participant TranslationNamespaces
  participant BlogSchema
  BlogPage->>TranslationNamespaces: load post and meta messages
  BlogPage->>blogPostSeoCopy: build title and description
  blogPostSeoCopy->>TranslationNamespaces: read audited candidate fields
  BlogPage->>BlogSchema: pass seoKey and published metadata
  BlogSchema->>blogPostSeoCopy: resolve structured-data copy
Loading

Fallback locale negotiation

sequenceDiagram
  participant Request
  participant fallbackContentRequestForPathname
  participant preferredFallbackContentLocale
  participant setFallbackContentLinkHeader
  Request->>fallbackContentRequestForPathname: match pathname to fallback route
  fallbackContentRequestForPathname-->>Request: return available locales
  Request->>preferredFallbackContentLocale: negotiate against available locales
  preferredFallbackContentLocale-->>Request: select fallback locale
  Request->>setFallbackContentLinkHeader: pass available locales
  setFallbackContentLinkHeader-->>Request: build alternate links
Loading
🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Only a CLI option tweak changed in production Swift; the new Swift file is test-only and its @unchecked Sendable state is lock-protected, so no actor-isolation regression.
Cmux Swift Blocking Runtime ✅ Passed No production Swift file adds waits/locks; the only new semaphore/NSLock usage is in cmuxTests test scaffolding, which the rule allows.
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR only changes web SEO/i18n pages and locale data; it doesn't touch the browser-automation routing files or commands covered by the rule.
Cmux Expensive Synchronous Load ✅ Passed Only production Swift change is ssh-session-attach arg validation/env handling; no new synchronous agent-history, JSON/JSONL, or main-actor load was added.
Cmux Cache Substitution Correctness ✅ Passed Diff only changes SEO, locale routing, and static blog locale lists; no persistence/history/undo/snapshot cache substitution found.
Cmux No Hacky Sleeps ✅ Passed No fixed sleeps or polling were added in production code; the new timer use is standard debounce/microtask handling for viewport/focus updates, not race-papering.
Cmux Algorithmic Complexity ✅ Passed PASS: New scans are over fixed static lists (18 blog posts, 1-2 locales); no new nested rescans or hot-path work on scalable user-owned collections.
Cmux Swift Concurrency ✅ Passed PASS: The PR changes only web/TS/JSON files; no Swift code is touched, so no legacy Swift concurrency patterns are introduced.
Cmux Swift @Concurrent ✅ Passed No Swift concurrency-annotation changes or invalid @concurrent/nonisolated async usage appear; the Swift diff is a sync CLI arg tweak plus test harness DispatchQueue async code.
Cmux Swift File And Package Boundaries ✅ Passed Only a 1-line fix in existing oversized CLI/cmux.swift plus a 382-line test file; no new oversized Swift file or package-boundary violation.
Cmux Swiftpm Lockfiles ✅ Passed Only test-file and CI-step changes were made; no Package.swift, .gitignore, or Xcode package-reference diff, so the lockfile rule isn’t triggered.
Cmux Swift Logging ✅ Passed PASS: the only production Swift file changed is CLI/cmux.swift, and its diff adds no print/debugPrint/dump/NSLog/Logger logging.
Cmux User-Facing Error Privacy ✅ Passed New CLI error is generic ('ssh-session-attach: --workspace requires a value') and exposes no vendor names, secrets, tokens, or payloads.
Cmux Full Internationalization ✅ Passed SEO copy now comes from next-intl helpers, and route-specific locale scoping matches message coverage (cmuxSsh en/ja; cmuxClaudeTeams/cmuxOmo/gpl en-only).
Cmux Swiftui State Layout ✅ Passed No SwiftUI view files were changed; the only Swift files touched are non-UI CLI/test code and contain no ObservableObject/@Published/GeometryReader patterns.
Cmux Architecture Rethink ✅ Passed Swift diff only tightens ssh-session-attach workspace/surface selection and adds test-only NSLock coverage; no new timing, observer, or split-owner pattern.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The PR diff is entirely web/TS/JSON/i18n; no Swift NSWindow/NSPanel/WindowGroup code was changed, so the auxiliary-window shortcut rule doesn't apply.
Cmux Source Artifacts ✅ Passed Changed paths are intentional source, docs, tests, and localization files; no artifact/cache/build-output paths appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No production Swift files under **/Sources/** changed; the only Swift edits are CLI/cmux.swift and a new test in cmuxTests/.
Cmux No Ambient Global State ✅ Passed PASS: The only production Swift change is an in-type guard in CMUXCLI; no new file-scope funcs/vars, namespace enums, or singletons were added.
Title check ✅ Passed The title clearly matches the main change: fixing residual blog metadata from an Ahrefs audit.
Description check ✅ Passed The description includes a solid Summary and Testing section, but it omits the Demo Video, Review Trigger, and Checklist sections from the template.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-seo-blog-audit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 210b427. Configure here.

Comment thread web/app/[locale]/(landing)/blog/cmux-omo/page.tsx
@greptile-apps

greptile-apps Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR aligns SEO metadata and locale availability across blog and landing pages. The main changes are:

  • Shared audited metadata selection for 11 blog posts, /guides, and /nightly.
  • Matching HTML, Open Graph, Twitter, and article schema copy.
  • Authored-locale restrictions for selected blog routes.
  • Consistent locale handling across redirects, alternates, sitemaps, navigation, and agent-readable variants.
  • Expanded SEO and route canonicalization tests.

Confidence Score: 5/5

This looks safe to merge.

  • The updated locale restrictions are consistent across routing, metadata, discovery, and agent-readable pages.
  • The metadata helpers use locale-specific message sources across the changed pages.
  • No blocking issue qualified for this follow-up review.

Important Files Changed

Filename Overview
web/i18n/audited-seo.ts Adds shared metadata selection for audited blog posts and landing pages.
web/i18n/locale-availability.ts Defines route-specific authored locales for fallback content.
web/proxy.ts Uses route-specific locale sets for negotiation, redirects, and alternate Link headers.
web/app/[locale]/components/blog-posts.ts Adds locale-aware filtering for blog discovery and navigation.
web/app/sitemap.ts Limits selected blog sitemap entries to authored locales.
web/app/lib/agent-page-paths.ts Applies authored-locale restrictions to agent-readable variants.
web/tests/seo.test.ts Expands coverage for metadata, locale discovery, sitemaps, and canonical redirects.
web/tests/agent-page-variants.test.ts Covers locale availability for Markdown and text page variants.

Reviews (18): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 210b427261

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/i18n/locale-availability.ts
@lawrencecchen lawrencecchen changed the base branch from feat-seo-site-audit to main July 12, 2026 00:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/messages/tr.json`:
- Line 631: Update the metaDescription translation to distinguish unconditional
layout restoration from conditional agent-session resumption, stating that agent
sessions are restored only when supported integrations, hooks, and native
session IDs are available. Preserve the existing cmux restart and crash-recovery
context without implying all listed agents are always resumed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8b0a9775-a330-45ba-8d08-862f385dcacc

📥 Commits

Reviewing files that changed from the base of the PR and between 0c3a602 and 19455ea.

📒 Files selected for processing (30)
  • web/app/[locale]/(landing)/blog/blog-schema.tsx
  • web/app/[locale]/(landing)/blog/claude-code-best-worktree-manager/page.tsx
  • web/app/[locale]/(landing)/blog/cmd-shift-u/page.tsx
  • web/app/[locale]/(landing)/blog/cmux-claude-teams/page.tsx
  • web/app/[locale]/(landing)/blog/cmux-home/page.tsx
  • web/app/[locale]/(landing)/blog/cmux-omo/page.tsx
  • web/app/[locale]/(landing)/blog/cmux-ssh/page.tsx
  • web/app/[locale]/(landing)/blog/gpl/page.tsx
  • web/app/[locale]/(landing)/blog/introducing-cmux/page.tsx
  • web/app/[locale]/(landing)/blog/page.tsx
  • web/app/[locale]/(landing)/blog/passkey-auth/page.tsx
  • web/app/[locale]/(landing)/blog/session-restore/page.tsx
  • web/app/[locale]/(landing)/blog/show-hn-launch/page.tsx
  • web/app/[locale]/(landing)/blog/unread-shortcuts/page.tsx
  • web/app/[locale]/(landing)/blog/zen-of-cmux/page.tsx
  • web/app/[locale]/(landing)/guides/page.tsx
  • web/app/[locale]/(landing)/nightly/page.tsx
  • web/app/[locale]/components/blog-pager.tsx
  • web/app/[locale]/components/blog-posts.ts
  • web/app/lib/agent-page-paths.ts
  • web/app/sitemap.ts
  • web/i18n/audited-seo.ts
  • web/i18n/locale-availability.ts
  • web/messages/bs.json
  • web/messages/en.json
  • web/messages/th.json
  • web/messages/tr.json
  • web/proxy.ts
  • web/tests/agent-page-variants.test.ts
  • web/tests/seo.test.ts

Comment thread web/messages/tr.json
},
"sessionRestore": {
"metaDescription": "cmux ile yeniden başlatma veya terminal çökmesinden sonra Claude Code, Codex, OpenCode, Gemini CLI, Antigravity CLI, Grok Build CLI ve diğer kodlama agent oturumlarını geri yükleme.",
"metaDescription": "cmux, yeniden başlatma veya terminal çökmesinden sonra Claude Code, Codex, OpenCode ve diğer kodlama ajanlarının düzenlerini ve oturumlarını geri yükler.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Qualify agent-session restoration in the metadata.

This description implies that cmux unconditionally restores all listed agent sessions. Session restoration actually depends on supported integrations, hooks, and native session IDs; distinguish layout restoration from conditional agent resumption.

Proposed wording
-      "metaDescription": "cmux, yeniden başlatma veya terminal çökmesinden sonra Claude Code, Codex, OpenCode ve diğer kodlama ajanlarının düzenlerini ve oturumlarını geri yükler.",
+      "metaDescription": "cmux, yeniden başlatma veya terminal çökmesinden sonra düzenleri geri yükler; desteklenen Claude Code, Codex, OpenCode ve diğer kodlama ajanlarının oturumlarını hooks ile sürdürür.",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"metaDescription": "cmux, yeniden başlatma veya terminal çökmesinden sonra Claude Code, Codex, OpenCode ve diğer kodlama ajanlarının düzenlerini ve oturumlarını geri yükler.",
"metaDescription": "cmux, yeniden başlatma veya terminal çökmesinden sonra düzenleri geri yükler; desteklenen Claude Code, Codex, OpenCode ve diğer kodlama ajanlarının oturumlarını hooks ile sürdürür.",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/messages/tr.json` at line 631, Update the metaDescription translation to
distinguish unconditional layout restoration from conditional agent-session
resumption, stating that agent sessions are restored only when supported
integrations, hooks, and native session IDs are available. Preserve the existing
cmux restart and crash-recovery context without implying all listed agents are
always resumed.

# Conflicts:
#	web/i18n/audited-seo.ts
#	web/tests/seo.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/tests/seo.test.ts (1)

1152-1166: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

plainSeoMessageLookup's colon-lead-in guard is missing the Khmer colon ().

The production filter in selectDescription (web/i18n/audited-seo.ts) treats /[::៖]\s*$/u as a list lead-in, but this test helper only checks /[::]\s*$/u. A Khmer blog-post field ending in would silently pass this guard instead of failing the "list lead-in requested as prose" check, even though the codebase elsewhere (e.g. this same file's km tests at lines 119, 628) explicitly exercises Khmer punctuation handling.

if (/[::]\s*$/u.test(value)) { throw new Error(SEO metadata requested list lead-in ${key} as prose); } return value;

🩹 Proposed fix
-    if (/[::]\s*$/u.test(value)) {
+    if (/[::៖]\s*$/u.test(value)) {
       throw new Error(`SEO metadata requested list lead-in ${key} as prose`);
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/tests/seo.test.ts` around lines 1152 - 1166, Update the colon-lead-in
check in plainSeoMessageLookup to include the Khmer colon alongside the existing
ASCII and fullwidth colon characters, matching selectDescription’s /[::៖]\s*$/u
behavior while preserving the current error handling.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@web/tests/seo.test.ts`:
- Around line 1152-1166: Update the colon-lead-in check in plainSeoMessageLookup
to include the Khmer colon alongside the existing ASCII and fullwidth colon
characters, matching selectDescription’s /[::៖]\s*$/u behavior while preserving
the current error handling.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c639bed1-5e43-4213-9acd-5c211c585336

📥 Commits

Reviewing files that changed from the base of the PR and between 19455ea and e34583a.

📒 Files selected for processing (5)
  • web/i18n/audited-seo.ts
  • web/messages/bs.json
  • web/messages/th.json
  • web/messages/tr.json
  • web/tests/seo.test.ts

@lawrencecchen lawrencecchen merged commit 50e1e7b into main Jul 12, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant